from maix import camera, display, image, time, app, touchscreen, uart, pinmap
import cv2
import numpy as np
import struct
import gc

# 80 fps or 60fps
cam = camera.Camera(320, 240, fps=60)
cam.constrast(60)
cam.saturation(50)
# cam.constrast(100)
# cam.saturation(0)
img = image.Image(320, 240)
img_copy = img
disp = display.Display()
ts = touchscreen.TouchScreen()

devices = uart.list_devices()
serial0 = uart.UART(devices[0], 115200)
pinmap.set_pin_function("A18", "UART1_RX")
pinmap.set_pin_function("A19", "UART1_TX")
device1 = "/dev/ttyS1"
serial1 = uart.UART(device1, 115200)

mode = 1

find_center_method = 1  # 1, 2
area_threshold = 80
pixels_threshold = 50
# thresholds = [[39, 59, 46, 66, 20, 40]]        # red
thresholds = [[65, 85, -28, -8, 66, 86]]        # yellow
# thresholds = [[0, 80, -120, -10, 0, 30]]        # green
# thresholds = [[0, 80, 30, 100, -120, -60]]    # blue

area_threshold2 = 300
pixels_threshold2 = 300

L_min = 0
L_max = 20
A_min = -11
A_max = 9
B_min = -9
B_max = 11 
binary_flag = 0
threshold_black = [L_min, L_max, A_min, A_max, B_min, B_max]
L_min1 = 66
L_max1 = 86
A_min1 = -15
A_max1 = 5
B_min1 = -15
B_max1 = 5
binary_flag = 0
threshold_white = [L_min1, L_max1, A_min1, A_max1, B_min1, B_max1]
binary_flag1 = 0
binary_flag2 = 0
# threshold_black = [1, 21, -13, 7, -7, 13]
# threshold_white = [65, 85, -12, 7, -12, 8]
# threshold_white = [threshold_white]
# threshold_black = [threshold_black]

rect_flag = False
rect_flag2 = False
rect_flag_mode3 = False
rect = np.zeros((9, 2), dtype="float32")
# last_rect = np.zeros((9, 2), dtype="float32")
last_centers = [(0, 0)] * 9
rect_x = [0] * 9
rect_y = [0] * 9
count_rect = 0

data1_flag = False

find_qizi = False
vul_points = [0]* 9 #存储盘中的物体  白 1 黑 2  无 0
prev_vul_points = [0] * 9 # 初始化先前的棋盘状态
changed_pieces = [] # 变化后的棋子信息
jxb = 0 # 机械臂放完棋子后会发送信息，标志位置一

count_change = 1
change_flag1 = False

task5_count = 0
task5_flag = False
#############################################从这开始是 下棋子的算法#####################################################
# 棋盘数组

# 黑子：X

# 白子：O

# 没有棋子：空字符串

board = [
     [" "," "," "],
     [" "," "," "],
     [" "," "," "],
]
SIZE = 3
# 检查赢了吗

def check_win(board, player):
    # Check rows and columns

    for i in range(SIZE):
        if all(board[i][j] == player for j in range(SIZE)) or \
           all(board[j][i] == player for j in range(SIZE)):
            return True
    # Check diagonals

    if all(board[i][i] == player for i in range(SIZE)) or \
       all(board[i][SIZE - 1 - i] == player for i in range(SIZE)):
        return True
    return False
# 检查平局了吗

def check_draw(board):
    return all(board[i][j] != ' ' for i in range(SIZE) for j in range(SIZE))

# 计算策略得分

def minimax(board, depth, is_maximizing):
    computer = 'X'
    player = 'O'

    if check_win(board, computer):
        return 10 - depth
    if check_win(board, player):
        return depth - 10
    if check_draw(board):
        return 0

    if is_maximizing:
        best_score = float('-inf')
        for i in range(SIZE):
            for j in range(SIZE):
                if board[i][j] == ' ':
                    board[i][j] = computer
                    score = minimax(board, depth + 1, False)
                    board[i][j] = ' '
                    best_score = max(score, best_score)
        return best_score
    else:
        best_score = float('inf')
        for i in range(SIZE):
            for j in range(SIZE):
                if board[i][j] == ' ':
                    board[i][j] = player
                    score = minimax(board, depth + 1, True)
                    board[i][j] = ' '
                    best_score = min(score, best_score)
        return best_score
# 计算下一步位置

def computer_move(board):
    if board == [
        [" "," "," "],
        [" "," "," "],
        [" "," "," "]
    ]:
        return 1,1
    best_score = float('-inf')
    move = (-1, -1)
    for i in range(SIZE):
        for j in range(SIZE):
            if board[i][j] == ' ':
                board[i][j] = 'X'
                score = minimax(board, 0, False)
                board[i][j] = ' '
                if score > best_score:
                    best_score = score
                    move = (i, j)
    if move != (-1, -1):
        # board[move[0]][move[1]] = 'X'

#        print(f"Computer places X at ({move[0]}, {move[1]})")

        return move[0], move[1]
# 检查该谁走了

def check_turn(board):
    x_count = sum(row.count("X") for row in board)
    o_count = sum(row.count("O") for row in board)
    return "X" if x_count == o_count else "O"

# 将数字转换为相应的字符

def convert_to_char(value):
    if value == 1:
        return "O"
    elif value == 2:
        return "X"
    else:
        return " "
#############################################从这开始是 下棋子的算法，不用修改END#####################################################

############################坐标排序函数##

def sort_points(points):#坐标排序函数

    # 按y坐标排序

    points = sorted(points, key=lambda p: p[1])
    # 将排序后的点分成三行，每行三个点

    rows = [points[i:i+3] for i in range(0, len(points), 3)]
    # 对每一行按x坐标排序

    sorted_points = [sorted(row, key=lambda p: p[0]) for row in rows]
    # 将排序后的点合并成一个列表

    sorted_points = [point for row in sorted_points for point in row]
    return sorted_points
############################坐标排序函数##END

def screen_lab():
    global L_min, L_max, A_min, A_max, B_min, B_max, binary_flag1, binary_flag2
    global L_min1, L_max1, A_min1, A_max1, B_min1, B_max1
    global threshold_black, threshold_white
    data = serial0.read()
    if data:
        if data[-1] == 0x0A:
            print(data, type(data))
            try:
                # print(data)
                data = data.decode("utf-8")
                # print(data)
                parts = data.split("\r\n")

                for part in parts:
                    try:
                        value = int(part)
                        L_min, L_max, A_min, A_max, B_min, B_max, binary_flag1 = L_max, A_min, A_max, B_min, B_max, binary_flag1, value
                        threshold_black = [L_min, L_max, A_min, A_max, B_min, B_max]
                    except ValueError:
                        # print("接收错误")
                        pass
                
                # 打印最新的两个数据
                print(f"L_min: {L_min}, L_max: {L_max}, A_min: {A_min}, A_max: {A_max}, B_min: {B_min}, B_max: {B_max}, binary_flag1: {binary_flag1}")
                print(f"threshold_black: {threshold_black}")

            except ValueError as e:
                print(f"Error decoding hexadecimal data: {e}")     
        elif data[-1] == 0x20:
            print(data, type(data))
            try:
                # print(data)
                data = data.decode("utf-8")
                # print(data)
                parts = data.split("  ")

                for part in parts:
                    try:
                        value = int(part)
                        L_min1, L_max1, A_min1, A_max1, B_min1, B_max1, binary_flag2 = L_max1, A_min1, A_max1, B_min1, B_max1, binary_flag2, value
                        threshold_white = [L_min1, L_max1, A_min1, A_max1, B_min1, B_max1]
                    except ValueError:
                        # print("接收错误")
                        pass
                
                # 打印最新的两个数据
                print(f"L_min1: {L_min1}, L_max1: {L_max1}, A_min1: {A_min1}, A_max1: {A_max1}, B_min1: {B_min1}, B_max1: {B_max1}, binary_flag2: {binary_flag2}")
                print(f"threshold_white: {threshold_white}")

            except ValueError as e:
                print(f"Error decoding hexadecimal data: {e}")     

def is_in_button(x, y, btn_pos):
    return x > btn_pos[0] and x < btn_pos[0] + btn_pos[2] and y > btn_pos[1] and y < btn_pos[1] + btn_pos[3]
def the_exit_button():
    exit_label = "Exit>"
    size = image.string_size(exit_label)
    exit_btn_pos = [300, 0, 5*2 + size.width(), 5 * 2 + size.height()] 
    # draw exit button
    img_copy.draw_string(270, 10, exit_label, image.COLOR_WHITE)
    # 图像按键坐标映射到屏幕上的坐标
    exit_btn_disp_pos = image.resize_map_pos(img.width(), img.height(), disp.width(), disp.height(), image.Fit.FIT_CONTAIN, exit_btn_pos[0], exit_btn_pos[1], exit_btn_pos[2], exit_btn_pos[3])
    x, y, pressed = ts.read()
    if is_in_button(x, y, exit_btn_disp_pos):
        app.set_exit_flag(True)

def key_clicked(btn_rects):
    global last_pressed
    x, y, pressed = ts.read()
    if pressed:
        for i, btn in enumerate(btn_rects):
            if is_in_button(x, y, btn):
                if not last_pressed:
                    last_pressed = True
                    return True, i, btn
    else:
        last_pressed = False
    return False, 0, []

def check_mode_switch(img : image.Image, disp_w, disp_h):
    global mode
    btns = [
        [0, 0, 100, 40],
    ]
    btn_rects_disp = [image.resize_map_pos(img.width(), img.height(), disp_w, disp_h, image.Fit.FIT_CONTAIN, btns[0][0], btns[0][1], btns[0][2], btns[0][3])]
    clicked, idx, rect = key_clicked(btn_rects_disp)
    if clicked:
        mode += 1
        if mode > 5:
            mode = 1
    img_copy.draw_string(2, 10, f"mode {mode}", color=image.COLOR_WHITE, scale=1)
    # img.draw_rect(btns[0][0], btns[0][1], btns[0][2], btns[0][3], image.COLOR_WHITE, 2)

def find_grid_centers(corners):
    """
    corners: List of 4 tuples representing the corners of the 3x3 grid in the order:
             top-left, top-right, bottom-right, bottom-left
    """
    # Define the 3x3 grid points in the normalized coordinate space
    grid_points = np.array([[0, 0], [1/3, 0], [2/3, 0], [1, 0],
                            [0, 1/3], [1/3, 1/3], [2/3, 1/3], [1, 1/3],
                            [0, 2/3], [1/3, 2/3], [2/3, 2/3], [1, 2/3],
                            [0, 1], [1/3, 1], [2/3, 1], [1, 1]])

    # Convert corners to numpy array
    src_points = np.array(corners, dtype=np.float32)

    # Define destination points for the perspective transform
    dst_points = np.array([[0, 0], [1, 0], [1, 1], [0, 1]], dtype=np.float32)

    # Compute the perspective transform matrix
    transform_matrix = cv2.getPerspectiveTransform(dst_points, src_points)

    # Transform grid points to image coordinate space
    transformed_points = cv2.perspectiveTransform(np.array([grid_points], dtype=np.float32), transform_matrix)[0]

    # Calculate the center points of the grid cells
    centers = []
    for i in range(0, 3):
        for j in range(0, 3):
            cx = (transformed_points[i * 4 + j][0] + transformed_points[i * 4 + j + 1][0] + 
                  transformed_points[(i + 1) * 4 + j][0] + transformed_points[(i + 1) * 4 + j + 1][0]) / 4
            cy = (transformed_points[i * 4 + j][1] + transformed_points[i * 4 + j + 1][1] + 
                  transformed_points[(i + 1) * 4 + j][1] + transformed_points[(i + 1) * 4 + j + 1][1]) / 4
            centers.append((int(cx), int(cy)))

    return centers

cam.skip_frames(30)           # 跳过开头的30帧
while not app.need_exit():
    # t = time.ticks_ms()
    img = cam.read()
    img_copy = img # 复制一份图像，防止干扰
    check_mode_switch(img, disp.width(), disp.height())
    the_exit_button()
    ################################################################################################
    screen_lab()
    if binary_flag1 == 1:
        img_binary = img.binary([threshold_black])
        disp.show(img_binary)
    elif binary_flag2 == 1:
        img_binary = img.binary([threshold_white])
        disp.show(img_binary)
    ################################################################################################
    receive_data = serial1.read()
    # print(receive_data)
    if receive_data:
        receive_data_str = receive_data.decode("utf-8")
        if receive_data_str == '1':
            print("找棋盘")
            mode = 1        
        #     data1_flag = False
        # if receive_data_str == '2':
        #     mode = 2
        # if receive_data_str == '3':
        #     mode = 3      
        if receive_data_str == '4':
            print("任务四")
            mode = 4   
        if receive_data_str == '5':
            print("任务五")
            mode = 5                 
        if receive_data_str == '8': # 任务四
            jxb = 1
        if receive_data_str == '9': # 任务五
            jxb = 1
            task5_count += 1

    # print(f"数据类型：{type(receive_data)}，接收的数据{receive_data}")
    # print(type(receive_data.decode))
    # print('test point--------------1-----模式：%d'%(mode))
    ################################################################################################
    # 开始找棋盘，循环50次后停止，进入mode2，需要主机发数据更改mode再次启动
    if mode == 1:
        img_cv = image.image2cv(img, False, False)
        gray = cv2.cvtColor(img_cv, cv2.COLOR_RGB2GRAY)

        # 高斯模糊去噪声
        blurred = cv2.GaussianBlur(gray, (5, 5), 0)
        # Bila = cv2.bilateralFilter(gray, 5, 100, 150) # 双边滤波
        # 边缘检测，阈值 0，150
        edged = cv2.Canny(blurred, 50, 150)

        # 闭运算
        kernel = np.ones((5, 5), np.uint8)
        closing = cv2.morphologyEx(edged, cv2.MORPH_CLOSE, kernel)
        # kernel = np.ones((3, 3), np.uint8)
        # dilated = cv2.dilate(edged, kernel, iterations=1)
        edges_close = cv2.morphologyEx(closing, cv2.MORPH_CLOSE, kernel)

        # disp.show(image.cv2image(edges_close, False, False))
        # 查找轮廓
        contours, _ = cv2.findContours(edges_close, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        if len(contours) > 0:
            # 筛选出最大的轮廓
            largest_contour = max(contours, key=cv2.contourArea)

            # 近似多边形
            epsilon = 0.02 * cv2.arcLength(largest_contour, True)
            approx = cv2.approxPolyDP(largest_contour, epsilon, True)

            # 如果找到的是一个四边形
            if len(approx) == 4:
                # print("rect found")
                corners = approx.reshape((4, 2))
                # 按顺序排列角点（左上、右上、右下、左下）
                rect = np.zeros((4, 2), dtype="int")
                s = corners.sum(axis=1)
                rect[0] = corners[np.argmin(s)]
                rect[2] = corners[np.argmax(s)]
                diff = np.diff(corners, axis=1)
                rect[1] = corners[np.argmin(diff)]
                rect[3] = corners[np.argmax(diff)]
                corners = rect

                # TODO: 这是外角点，可以优化一下找到线中心的点，这里直接写死往内收拢 1 个像素
                half_x = 1
                half_y = 1
                corners[0] += (half_x, half_y)
                corners[1] += (-half_x, half_y)
                corners[2] += (-half_x, -half_y)
                corners[3] += (half_x, -half_y)

                # 绘制顶点和轮廓
                for corner in corners:
                    cv2.circle(img_cv, tuple(corner), 4, (0, 255, 0), -1)

                # 绘制四边路径性
                # cv2.drawContours(img_cv, [approx], -1, (0, 255, 0), 1)

                # 洪泛填充外部，如果棋盘外部的背景和棋盘内部的背景相同且后面用了找色块的方式找才需要这一步
                if find_center_method == 2:
                    img.flood_fill(corners[0][0] - 5, corners[0][1] - 5, 0.3, 0.3, image.COLOR_BLUE)
                    # img.flood_fill(corners[1][0] - 5, corners[1][1] + 5, 0.5, 0.05, image.COLOR_BLUE)
                    # img.flood_fill(corners[0][0] + 5, corners[0][1] + 5, 0.5, 0.05, image.COLOR_BLUE)
                    # img.flood_fill(corners[0][0] + 5, corners[0][1] - 5, 0.5, 0.05, image.COLOR_BLUE)

                centers = []
                # 找格子中心点方法一：直接根据顶点计算
                if find_center_method == 1:
                    # 根据顶点找出中心点
                    centers  = find_grid_centers(corners)
                    for i in range(9):
                        for j in range(2):
                            if abs(centers[i][j] - last_centers[i][j] < 3):
                                count_rect += 1
                                # print(count_rect)
                            else:
                                count_rect = 0
                                print("识别有误！")       
                    if count_rect >= 50:
                        print("识别成功！")
                        # rect_flag = True # 模式一下准确识别50次棋盘后不识别棋盘，释放空间
                        # rect_flag2 = True #串口发送标志位
                        find_qizi = True
                        mode = 2
                        for i in range(9):
                            print(f"第{i}个方格，x：{centers[i][0]}, y：{centers[i][1]}")
                        count_rect = 0
                    rect_x = [my_rect[0] for my_rect in centers]
                    rect_y = [my_rect[1] for my_rect in centers]
                    for i in range(9):
                        last_centers[i] = centers[i]
                # 找格子中心点方法二： 找色块的方式来确定中心点
                elif find_center_method == 2:                # 上面出来的结果已经是 点从左上顺时针
                    roi = [corners[:,0].min(), corners[:,1].min(), corners[:,0].max() - corners[:,0].min(), corners[:,1].max() - corners[:,1].min()]
                    img.draw_rect(roi[0], roi[1], roi[2], roi[3], image.COLOR_WHITE)
                    blobs = img.find_blobs(thresholds, roi=roi, x_stride=2, y_stride=1, area_threshold=area_threshold, pixels_threshold=pixels_threshold)
                    for b in blobs:
                        centers.append((b.cx(), b.cy()))
                    # 对找到的中心点进行编号, y + x 最大就是右下角，最小就是左上角， y-x 最大就是左下角，y-x 最小就是右上角，其它几个点根据在旁边两个点中间判断
                    if len(centers) == 9:
                        centers = np.array(centers)
                        rect = np.zeros((9, 2), dtype="int")
                        s = centers.sum(axis=1)
                        idx_0 = np.argmin(s)
                        idx_8 = np.argmax(s)
                        diff = np.diff(centers, axis=1)
                        idx_2 = np.argmin(diff)
                        idx_6 = np.argmax(diff)
                        rect[0] = centers[idx_0]
                        rect[2] = centers[idx_2]
                        rect[6] = centers[idx_6]
                        rect[8] = centers[idx_8]
                        #   其它点
                        calc_center = (rect[0] + rect[2] + rect[6] + rect[8]) / 4
                        mask = np.zeros(centers.shape[0], dtype=bool)
                        idxes = [1, 3, 4, 5, 7]
                        mask[idxes] = True
                        others = centers[mask]
                        idx_l = others[:,0].argmin()
                        idx_r = others[:,0].argmax()
                        idx_t = others[:,1].argmin()
                        idx_b = others[:,1].argmax()
                        found = np.array([idx_l, idx_r, idx_t, idx_b])
                        mask = np.isin(range(len(others)), found, invert=False)
                        idx_c = np.where(mask == False)[0]
                        if len(idx_c) == 1:
                            rect[1] = others[idx_t]
                            rect[3] = others[idx_l]
                            rect[4] = others[idx_c]
                            rect[5] = others[idx_r]
                            rect[7] = others[idx_b]
                        else:
                            # 等于 45度的情况
                            print("== 45 degree")
                        centers = rect
                else:
                    raise Exception("find_center_method value error")

                # 画出中心点
                # 写编号
                if len(centers) == 9:
                    for i in range(9):
                        # x, y = centers[i][0], centers[i][1]
                        x, y = rect_x[i], rect_y[i]
                        cv2.circle(img_cv, (x, y), 2, (0, 255, 0), -1)
                        img_copy.draw_string(x, y, f"{i + 1}", image.COLOR_WHITE, scale=2, thickness=-1)
    for i in range(9):                    
        img_copy.draw_string(rect_x[i], rect_y[i], f"{i + 1}", image.COLOR_WHITE, scale=2, thickness=-1)
    ################################################################################################
    # 扫描棋子
    if find_qizi:
        for i in range(9):
            img_copy.draw_rect(rect_x[i]-25, rect_y[i]-25, 50, 50, image.COLOR_RED,thickness=2)
            _blobs = img.find_blobs([threshold_white,threshold_black],
                                        roi = [rect_x[i]-25, rect_y[i]-25, 50, 50],
                                        x_stride=2, y_stride=1,
                                        pixels_threshold=area_threshold2, area_threshold=pixels_threshold2)

            if _blobs == [] :#判断是否为空
                # print('test point--------------2-----%d 为无'%(i+1))
                vul_points[i] = 0

            for blob in _blobs:
                # print(f"第{i+1}个棋子大小, 面积：{blob.area()}, 宽：{blob.w()}, 高：{blob.h()}")
                # 滤除棋盘边框
                if blob.w() > 45 and blob.h() > 45:  # 假设棋盘边框较大
                    continue
                if blob.w() < 18 and blob.h() < 18:  # 假设小于就不用
                    continue
                # 进一步验证色块形状是否接近圆形（判断宽高比）
                aspect_ratio = blob.w() / blob.h()
                if aspect_ratio < 0.6 or aspect_ratio > 1.4:  # 假设棋子的宽高比接近1
                    continue
                if blob.code() == 1:#白色
                    enclosing_circle = blob.enclosing_circle()
                    img_copy.draw_circle(enclosing_circle[0], enclosing_circle[1], enclosing_circle[2], image.COLOR_PURPLE, thickness=2)
                    img_copy.draw_cross(enclosing_circle[0],enclosing_circle[1],image.COLOR_PURPLE,thickness=2)
                    # print('test point--------------2-----%d 为白'%(i+1))

                    vul_points[i] = 1
                elif blob.code() == 2:   #黑色
                    enclosing_circle = blob.enclosing_circle()
                    img_copy.draw_circle(enclosing_circle[0], enclosing_circle[1], enclosing_circle[2], image.COLOR_ORANGE, thickness=2)
                    img_copy.draw_cross(enclosing_circle[0],enclosing_circle[1],image.COLOR_ORANGE,thickness=2)
                    # print('test point--------------2-----%d 为黑'%(i+1))
                    vul_points[i] = 2
                prev_vul_points[i] = vul_points[i] # 上一次棋盘的坐标信息
        # print('test point--------------2-----棋盘')
        # print(vul_points) # 棋盘局势
        # print('test point--------------2--------')
    ################################################################################################
    # 调试使用，
    # 比较当前状态和之前状态，找出变动的棋子
    # if any(point != 0 for point in vul_points):
    #     for i in range(9):
    #         if vul_points[i] != prev_vul_points[i]:
    #             changed_pieces.append(i + 1)
    #             change_flag1 = True
    #             count_change += 1
            
    # change_data_change = False
    # if change_data_change == False: # 只发一次
    #     if change_flag1 == True:
    #         print(changed_pieces[-1])
    #         data_change = struct.pack('>HBB', changed_pieces[-1], 0X0D, 0x0A)
    #         serial1.write(data_change)
    #         change_data_change = True
    #         change_flag1 = False
    ################################################################################################
    if(mode == 2):
        task5_count = 0
    ################################################################################################
    # 在mode4下，机械臂发送‘111’给cam，然后开始决策，等到人下完，就再次发送‘111’
    # 开始状态可以选择写死在5的位置，或者发‘111’给cam
    if(mode == 4):#在mode = 之前机械臂也要同时开始运动

        # print('test point--------------mode4-----')#第一步需要设置一个位置，这个位置由下位机提供

        #例如接收 1-9数字或者不进行传参，只在机械臂运动完成以后发送完成标志

        #收到完成标志以后就说明可以摄像头读取

        if(jxb == 1):#表示可以运行，机械臂已经归为了

        # 上一步就是扫描棋子，这一步骤 可以直接进行下棋

        #装置执黑棋先行与人对弈（第 1 步方格可设置），若人应对的第 1 步白

        #棋有错误，装置能获胜。

        # 转换 initial_state

            initial_state = vul_points
            converted_state = [convert_to_char(value) for value in initial_state]
            # 将一维数组转换为二维数组

            board = [converted_state[i:i + 3] for i in range(0, len(converted_state), 3)]
            print(board)
            #这个模式下是我拿白先，机器是黑色的。

            # 下棋策略

            if check_win(board, 'O'):
                print("你赢啦!")

                data = struct.pack('>BBB', 0x01, 0x0D, 0x0A)
                serial1.write(data)

                mode = 0 # 下完棋回归模式？
            elif check_win(board, 'X'):
                print("我赢啦！")

                data = struct.pack('>BBB', 0x02, 0x0D, 0x0A)
                serial1.write(data)
                
                mode = 0
            elif check_draw(board):
                print("平局啦！")

                data = struct.pack('>BBB', 0x03, 0x0D, 0x0A)
                serial1.write(data)

                mode = 0
            elif check_turn(board) == "X":
                # 计算下一步棋子放在哪里
                line, row = computer_move(board)
                print('test point--------------mode4-----下棋的坐标为')
                print(line)
                print(row)
                move_index = line*3 + (row+1)
                print('test point--------------mode4-----运行完成-落点为:%d' %move_index)
                #也是需要发给东西的地方
                # 向机械臂发送了一个字符串，其中包含了下一步棋子的位置。例如，如果 move_index 是 5，那么发送的字符串就是 “AA5”，表示下在第 5 个格子。
                data_jxb = struct.pack('>HBB', move_index, 0x0D, 0x0A)
                serial1.write(data_jxb)


            elif check_turn(board) == "O":
                print("该你下了！")
                data = struct.pack('>BBB', 0x04, 0x0D, 0x0A)
                serial1.write(data)
                
            jxb = 0
    ################################################################################################
    elif mode == 5:#在mode = 之前机械臂也要同时开始运动
        if(task5_flag == False):
            if(task5_count == 1):
                if(vul_points[4] == 0):
                    data_jxb = struct.pack('>HBB', vul_points[4]+1, 0x0D, 0x0A)
                    serial1.write(data_jxb)
                    task5_flag = True
                    print('test point--------------mode5-----运行完成-落点为:%d' %(vul_points[4]+1))
                elif(vul_points[0] == 0):
                    data_jxb = struct.pack('>HBB', vul_points[0]+1, 0x0D, 0x0A)
                    serial1.write(data_jxb)
                    task5_flag = True
                    print('test point--------------mode5-----运行完成-落点为:%d' %(vul_points[0]+1))
                else:
                    data_jxb = struct.pack('>HBB', vul_points[4]+1, 0x0D, 0x0A)
                    serial1.write(data_jxb)
                    task5_flag = True
                    print('test point--------------mode5-----运行完成-落点为:%d' %(vul_points[4]+1))                
                jxb = 0
        # print('test point--------------mode5-----')#第一步需要设置一个位置，这个位置由下位机提供

        #例如接收 1-9数字或者不进行传参，只在机械臂运动完成以后发送完成标志

        #收到完成标志以后就说明可以摄像头读取
        if(task5_count > 1):
            if(jxb == 1): #表示可以运行，机械臂已经归为了

            # 人执黑先行，装置能正确放置白棋子以保持不输棋。

            # 转换 initial_state

                initial_state = vul_points
                converted_state = [convert_to_char(value) for value in initial_state]
                # 将一维数组转换为二维数组

                board = [converted_state[i:i + 3] for i in range(0, len(converted_state), 3)]
                print(board)
                #这个模式下是我拿白先，机器是黑色的。

                # 下棋策略

                if check_win(board, 'X'):
                    print("我赢啦!")

                    data = struct.pack('>BBB', 0x02, 0x0D, 0x0A)
                    serial1.write(data)
                    
                    mode = 0
                elif check_win(board, 'O'):
                    print("你赢啦！")

                    data = struct.pack('>BBB', 0x01, 0x0D, 0x0A)
                    serial1.write(data)

                    mode = 0 # 下完棋回归模式？
                elif check_draw(board):
                    print("平局啦！")

                    data = struct.pack('>BBB', 0x03, 0x0D, 0x0A)
                    serial1.write(data)

                elif check_turn(board) == "O":# 电脑是x 是 hei

                    # 计算下一步棋子放在哪里

                    #打印

                    line,row = computer_move(board)
                    print('test point--------------mode5-----下棋的坐标为')
                    print(line)
                    print(row)
                    move_index = line*3 + (row+1)
                    print('test point--------------mode5-----运行完成-落点为:%d' %move_index)
                    #也是需要发给东西的地方
                    # 向机械臂发送了一个字符串，其中包含了下一步棋子的位置。例如，如果 move_index 是 5，那么发送的字符串就是 “AA5”，表示下在第 5 个格子。
                    data_jxb = struct.pack('>HBB', move_index, 0x0D, 0x0A)
                    serial1.write(data_jxb)

                elif check_turn(board) == "X":
                    data = struct.pack('>BBB', 0x04, 0x0D, 0x0A)
                    serial1.write(data)                
                    print("该你下了！")
                jxb = 0
    ################################################################################################
    # 发送棋盘局势
    # if data1_flag == False:
    #     if all(point != 0 for point in vul_points):
    #         data1 = struct.pack('>BBBBBBBBBBB', vul_points[0], vul_points[1], vul_points[2], vul_points[3], vul_points[4], vul_points[5],vul_points[6], vul_points[7], vul_points[8], 0x0D, 0x0A)
    #         # time.sleep_ms(1000)
    #         serial1.write(data1)
    #         print(data1)
    #         data1_flag = True

    ################################################################################################
    # img_show = image.cv2image(edged)
    disp.show(img_copy)
    # print(f"time: {time.ticks_ms() - t}ms, fps: {1000 / (time.ticks_ms() - t)}")
    # del cam
    gc.collect() # 回收垃圾
